class_name MessageSystem
extends BaseSystem

#region 属性
@export var auto_sync_interval:float = 0.1
@export var auto_gc_interval:float = 10
@export var maximum_message_amount:int = 200
var message_queue:Array[Message] = []
var observer_dict:Dictionary = {}
var connections:Dictionary = {}
var id = 0
var is_block:bool = false
#endregion
#region 字段
#endregion
#region 信号
#endregion

#region 基类方法
func init_system(args = null):
	super(args)
	var sync_timer = Timer.new()
	sync_timer.name = "SyncTimer"
	add_child(sync_timer)
	sync_timer.wait_time = auto_sync_interval
	connections["SyncTimerTimeOut"] = ConnectObj.new(sync_timer.timeout,[_on_sync_timer_time_out])
	sync_timer.autostart = true
	var gc_timer = Timer.new()
	gc_timer.name = "GCTimer"
	add_child(gc_timer)
	gc_timer.wait_time = auto_gc_interval
	connections["GCTimerTimeOut"] = ConnectObj.new(gc_timer.timeout,[_on_gc_timer_time_out])
	gc_timer.autostart = true
#endregion
#region 公共方法
## 添加监听
## 如果 m_tag == "" 则只要namespace符合就会发消息
func observe(m_observer:Node,m_namespace:String,m_tag:String = "",m_callback:Callable = Callable(),m_maximum_processing_time:float = 5,m_is_sync_previous_message:bool = true) -> int:
	if m_namespace:
		var tags:Dictionary = observer_dict.get_or_add(m_namespace,{})
		var observers:Array = tags.get_or_add(m_tag,[])
		var message_observer = MessageObserver.new(m_observer,m_callback,m_maximum_processing_time,m_is_sync_previous_message)
		observers.append(message_observer)
		if m_is_sync_previous_message:
			sync_message_by_observer(message_observer)
		return message_observer.id
	return -1
## 发消息
func send_message(m_namespace:String,m_tag:String = "",args:Array = []):
	var message:Message = Message.new(m_namespace,m_tag,args)
	message_queue.push_back(message)
	sync_message(message)
## 断开指定id的监听
func disobserve_by_id(id:int):
	if id < 0:
		return
	for m_namespace in observer_dict.keys():
		for m_tag in observer_dict[m_namespace].keys():
			var observers:Array[MessageObserver] = observer_dict[m_namespace][m_tag]
			var res = observers.filter(func(o:MessageObserver):return o.id == id)
			for o in res:
				observers.erase(o)
				return
## 断开指定监听者的监听
func disobserve_by_observer(observer:Node):
	for m_namespace in observer_dict.keys():
		for m_tag in observer_dict[m_namespace].keys():
			var observers:Array[MessageObserver] = observer_dict[m_namespace][m_tag]
			var res = observers.filter(func(o:MessageObserver):return o.observer == observer)
			for o in res:
				observers.erase(o)
## 清除指定tag
func clear_tag(m_namespace:String,m_tag:String):
	if observer_dict.has(m_namespace) and observer_dict[m_namespace].has(m_tag):
		observer_dict[m_namespace].erase(m_tag)
## 清除指定namespace
func clear_namespace(m_namespace:String):
	if observer_dict.has(m_namespace):
		observer_dict.erase(m_namespace)
## 同步某个消息
func sync_message(message:Message):
	if is_block:
		return
	for observer in get_observers(message.m_namespace,message.m_tag):
		if observer.check_is_valid():
			observer.excute_callback(message)
## 同步某个监听者的消息（只有支持第一次创建监听时允许同步先前消息的会触发）
func sync_message_by_observer(message_observer:MessageObserver):
	if is_block:
		return
	for message in message_queue:
		message_observer.excute_callback(message,true)
## 同步所有消息
func sync_all_message():
	if is_block:
		return
	for message in message_queue:
		for observer in get_observers(message.m_namespace,message.m_tag):
			if observer.check_is_valid():
				observer.excute_callback(message)
## 设置消息系统的阻塞状态
func set_block(block:bool):
	is_block = block
## 设置指定的id的监听阻塞
func block_observer_by_id(id:int,block:bool):
	if id < 0:
		return
	for m_namespace in observer_dict.keys():
		for m_tag in observer_dict[m_namespace].keys():
			var observers:Array[MessageObserver] = observer_dict[m_namespace][m_tag]
			var res = observers.filter(func(o:MessageObserver):return o.id == id)
			for o in res:
				o.is_block = block
				return
## 返回所有符合的Observer
## m_namespace，m_tag:Message的属性
func get_observers(m_namespace:String,m_tag:String) -> Array[MessageObserver]:
	var res:Array[MessageObserver] = []
	if m_tag != "":
		if observer_dict.has(m_namespace) and observer_dict[m_namespace].has(m_tag):
			res.append_array(observer_dict[m_namespace][m_tag])
		if observer_dict.has(m_namespace) and observer_dict[m_namespace].has(""):
			res.append_array(observer_dict[m_namespace][""])
		return res
	else:
		if observer_dict.has(m_namespace):
			for tag in observer_dict[m_namespace]:
				res.append_array(observer_dict[m_namespace][tag])
		return res
## 返回一个唯一的id
func get_id() ->int:
	var cur_id = id
	id += 1
	return cur_id
#endregion
#region 私有方法
func _on_sync_timer_time_out():
	sync_all_message()
func _on_gc_timer_time_out():
	for m_namespace in observer_dict.keys():
		for m_tag in observer_dict[m_namespace].keys():
			var observers:Array[MessageObserver] = observer_dict[m_namespace][m_tag]
			observer_dict[m_namespace][m_tag] = observers.filter(func(o:MessageObserver):return o.check_is_valid())
			if observer_dict[m_namespace][m_tag].size() == 0:
				observer_dict[m_namespace].erase(m_tag)
		if observer_dict[m_namespace].is_empth():
			observer_dict.erase(m_namespace)
#endregion
#region 生命周期函数
func _notification(what: int) -> void:
	if what == NOTIFICATION_WM_CLOSE_REQUEST:
		for connection:ConnectObj in connections.values():
			connection.disconnect_all()
		connections.clear()
#endregion
